home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / filesyst / dosfs / dosfsck_.z / dosfsck_ / dosfsck / check.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-11  |  15.9 KB  |  602 lines

  1. /* check.c  -  Check and repair a PC/MS-DOS file system */
  2.  
  3. /* Written 1993 by Werner Almesberger */
  4.  
  5.  
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <limits.h>
  9. #include <time.h>
  10.  
  11. #include "common.h"
  12. #include "dosfsck.h"
  13. #include "io.h"
  14. #include "fat.h"
  15. #include "file.h"
  16. #include "check.h"
  17.  
  18.  
  19. static DOS_FILE *root;
  20.  
  21.  
  22. #define MODIFY(p,i,v) \
  23.   ((p->dir_ent.i = v), \
  24.   fs_write(p->offset+((char *) &p->dir_ent.i-(char *) &p->dir_ent), \
  25.    sizeof(p->dir_ent.i),&p->dir_ent.i))
  26.  
  27.  
  28. static char *path_name(DOS_FILE *file)
  29. {
  30.     static char path[PATH_MAX*2];
  31.  
  32.     if (!file) *path = 0;
  33.     else {
  34.     if (strlen(path_name(file->parent)) > PATH_MAX)
  35.         die("Path name too long.");
  36.     strcat(path,"/");
  37.     strcpy(strrchr(path,0),file_name(file->dir_ent.name));
  38.     }
  39.     return path;
  40. }
  41.  
  42.  
  43. static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
  44.           /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
  45.  
  46.  
  47. /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
  48.  
  49. int date_dos2unix(unsigned short time,unsigned short date)
  50. {
  51.     int month,year,secs;
  52.  
  53.     month = ((date >> 5) & 15)-1;
  54.     year = date >> 9;
  55.     secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
  56.       ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
  57.       month < 2 ? 1 : 0)+3653);
  58.                        /* days since 1.1.70 plus 80's leap day */
  59.     return secs;
  60. }
  61.  
  62.  
  63. static char *file_stat(DOS_FILE *file)
  64. {
  65.     static char temp[100];
  66.     struct tm *tm;
  67.     char tmp[100];
  68.     int date;
  69.  
  70.     date = date_dos2unix(CF_LE_W(file->dir_ent.time),CF_LE_W(file->
  71.       dir_ent.date));
  72.     tm = localtime(&date);
  73.     strftime(tmp,99,"%H:%M:%S %b %d %Y",tm);
  74.     sprintf(temp,"  Size %u bytes, date %s",CF_LE_L(file->dir_ent.size),tmp);
  75.     return temp;
  76. }
  77.  
  78.  
  79. static int bad_name(unsigned char *name)
  80. {
  81.     int bad,i,spc;
  82.  
  83.     bad = 0;
  84.     for (i = 0; i < MSDOS_NAME; i++) {
  85.     if (name[i] < ' ' || name[i] == 0x7f) bad += 2;
  86.     else if (name[i] > 0x7f) bad++;
  87.         else if (strchr("*?<>|\"\\/",name[i])) bad += 2;
  88.     }
  89.     spc = 0;
  90.     for (i = 0; i < 8; i++)
  91.     if (name[i] == ' ') spc++;
  92.     else {
  93.         bad += spc;
  94.         spc = 0;
  95.     }
  96.     spc = 0;
  97.     for (i = 8; i < 11; i++)
  98.     if (name[i] == ' ') spc++;
  99.     else {
  100.         bad += spc;
  101.         spc = 0;
  102.     }
  103.     return bad > 5;
  104. }
  105.  
  106.  
  107. static void drop_file(DOS_FS *fs,DOS_FILE *file)
  108. {
  109.     int cluster;
  110.  
  111.     MODIFY(file,name[0],DELETED_FLAG);
  112.     for (cluster = CF_LE_W(file->dir_ent.start); cluster > 0 && cluster <
  113.       fs->clusters+2; cluster = next_cluster(fs,cluster))
  114.     set_owner(fs,cluster,NULL);
  115. }
  116.  
  117.  
  118. static void truncate_file(DOS_FS *fs,DOS_FILE *file,int clusters)
  119. {
  120.     int walk,next,prev,deleting;
  121.  
  122.     walk = CF_LE_W(file->dir_ent.start);
  123.     prev = 0;
  124.     if (deleting = !clusters) MODIFY(file,start,CT_LE_L(0));
  125.     while (walk > 0) {
  126.     next = next_cluster(fs,walk);
  127.     if (deleting) set_fat(fs,walk,0);
  128.     else if (deleting = !--clusters) set_fat(fs,walk,-1);
  129.     prev = walk;
  130.     walk = next;
  131.     }
  132. }
  133.  
  134.  
  135. static void auto_rename(DOS_FILE *file)
  136. {
  137.     DOS_FILE *first,*walk;
  138.     int number;
  139.  
  140.     first = file->parent ? file->parent->first : root;
  141.     number = 0;
  142.     while (1) {
  143.     sprintf(file->dir_ent.name,"FSCK%04d",number);
  144.     strncpy(file->dir_ent.ext,"REN",3);
  145.     for (walk = first; walk; walk = walk->next)
  146.         if (walk != file && !strncmp(walk->dir_ent.name,file->dir_ent.
  147.           name,MSDOS_NAME)) break;
  148.     if (!walk) return;
  149.     number++;
  150.     }
  151.     die("Can't generate a unique name.");
  152. }
  153.  
  154.  
  155. static void rename_file(DOS_FILE *file)
  156. {
  157.     unsigned char name[46];
  158.     unsigned char *walk,*here;
  159.  
  160.     while (1) {
  161.     printf("New name: ");
  162.     fflush(stdout);
  163.     if (fgets(name,45,stdin)) {
  164.         if (here = strchr(name,'\n')) *here = 0;
  165.         for (walk = strrchr(name,0); walk >= name && (*walk == ' ' ||
  166.           *walk == '\t'); walk--);
  167.         walk[1] = 0;
  168.         for (walk = name; *walk == ' ' || *walk == '\t'; walk++);
  169.         if (file_cvt(walk,file->dir_ent.name)) return;
  170.     }
  171.     }
  172. }
  173.  
  174.  
  175. static int handle_dot(DOS_FS *fs,DOS_FILE *file,int dots)
  176. {
  177.     char *name;
  178.  
  179.     name = strncmp(file->dir_ent.name,MSDOS_DOT,MSDOS_NAME) ? ".." : ".";
  180.     if (!(file->dir_ent.attr & ATTR_DIR)) {
  181.     printf("%s\n  Is a non-directory.\n",path_name(file));
  182.     if (interactive)
  183.         printf("1) Drop it\n2) Auto-rename\n3) Rename\n"
  184.           "4) Convert to directory\n");
  185.     else printf("  Auto-renaming it.\n");
  186.     switch (interactive ? get_key("1234","?") : '2') {
  187.         case '1':
  188.         drop_file(fs,file);
  189.         return 1;
  190.         case '2':
  191.         auto_rename(file);
  192.         printf("  Renamed to %s\n",file_name(file->dir_ent.name));
  193.         return 0;
  194.         case '3':
  195.         rename_file(file);
  196.         return 0;
  197.         case '4':
  198.         MODIFY(file,size,CT_LE_L(0));
  199.         MODIFY(file,attr,file->dir_ent.attr | ATTR_DIR);
  200.         break;
  201.     }
  202.     }
  203.     if (!dots) {
  204.     printf("Root contains directory \"%s\". Dropping it.\n",name);
  205.     drop_file(fs,file);
  206.     return 1;
  207.     }
  208.     return 0;
  209. }
  210.  
  211.  
  212. static int check_file(DOS_FS *fs,DOS_FILE *file)
  213. {
  214.     DOS_FILE *owner;
  215.     int clusters,prev,curr,this,expect,restart;
  216.     int walk,clusters2;
  217.  
  218.     if (file->dir_ent.attr & ATTR_DIR) {
  219.     if (CF_LE_L(file->dir_ent.size)) {
  220.         printf("%s\n  Directory has non-zero size. Fixing it.\n",
  221.           path_name(file));
  222.         MODIFY(file,size,CT_LE_L(0));
  223.     }
  224.     if (file->parent && !strncmp(file->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) {
  225.         expect = CF_LE_W(file->parent->dir_ent.start);
  226.         if (CF_LE_W(file->dir_ent.start) != expect) {
  227.         printf("%s\n  Start (%d) does not point to parent (%d)\n",
  228.           path_name(file),CF_LE_W(file->dir_ent.start),expect);
  229.         MODIFY(file,start,CT_LE_W(expect));
  230.         }
  231.         return 0;
  232.     }
  233.     if (file->parent && !strncmp(file->dir_ent.name,MSDOS_DOTDOT,
  234.       MSDOS_NAME)) {
  235.         expect = file->parent->parent ? CF_LE_W(file->parent->parent->
  236.           dir_ent.start) : 0;
  237.         if (CF_LE_W(file->dir_ent.start) != expect) {
  238.         printf("%s\n  Start (%d) does not point to .. (%d)\n",
  239.           path_name(file),CF_LE_W(file->dir_ent.start),expect);
  240.         MODIFY(file,start,CT_LE_W(expect));
  241.         }
  242.         return 0;
  243.     }
  244.     }
  245.     if (CF_LE_W(file->dir_ent.start) >= fs->clusters+2) {
  246.     printf("%s\n  Start cluster beyond limit (%u > %d). Truncating file.\n",
  247.       path_name(file),CF_LE_W(file->dir_ent.start),fs->clusters+1);
  248.     MODIFY(file,start,CT_LE_W(0));
  249.     }
  250.     clusters = prev = 0;
  251.     for (curr = CF_LE_W(file->dir_ent.start) ? CF_LE_W(file->dir_ent.start) :
  252.       -1; curr != -1; curr = next_cluster(fs,curr)) {
  253.     if (!fs->fat[curr].value || bad_cluster(fs,curr)) {
  254.         printf("%s\n  Contains a %s cluster (%d). Assuming EOF.\n",
  255.           path_name(file),fs->fat[curr].value ? "bad" : "free",curr);
  256.         if (prev) set_fat(fs,prev,-1);
  257.         else MODIFY(file,start,CT_LE_W(0));
  258.         break;
  259.     }
  260.     if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) <=
  261.       clusters*fs->cluster_size) {
  262.         printf("%s\n  File size is %u bytes, cluster chain length is > %u "
  263.           "bytes.\n  Truncating file to %u bytes.\n",path_name(file),
  264.           CF_LE_L(file->dir_ent.size),clusters*fs->cluster_size,
  265.           CF_LE_L(file->dir_ent.size));
  266.         truncate_file(fs,file,clusters);
  267.         break;
  268.     }
  269.     if (owner = get_owner(fs,curr)) {
  270.         printf("%s  and\n",path_name(owner));
  271.         printf("%s\n  share clusters.\n",path_name(file));
  272.         clusters2 = 0;
  273.         for (walk = CF_LE_W(owner->dir_ent.start); walk > 0; walk =
  274.           next_cluster(fs,walk))
  275.         if (walk == curr) break;
  276.         else clusters2++;
  277.         restart = file->dir_ent.attr & ATTR_DIR;
  278.         if (interactive)
  279.         printf("1) Truncate first to %u bytes%s\n"
  280.           "2) Truncate second to %u bytes\n",clusters*fs->cluster_size,
  281.           restart ? " and restart" : "",clusters2*fs->cluster_size);
  282.         else printf("  Truncating second to %u bytes.\n",clusters2*
  283.           fs->cluster_size);
  284.         if (interactive && get_key("12","?") == '1') {
  285.         prev = 0;
  286.         clusters = 0;
  287.         for (this = CF_LE_W(owner->dir_ent.start); this > 0; this =
  288.           next_cluster(fs,this)) {
  289.             if (this == curr) {
  290.             if (prev) set_fat(fs,prev,-1);
  291.             else MODIFY(owner,start,CT_LE_W(0));
  292.             MODIFY(owner,size,CT_LE_L(clusters*fs->cluster_size));
  293.             if (restart) return 1;
  294.             while (this > 0) {
  295.                 set_owner(fs,this,NULL);
  296.                 this = next_cluster(fs,this);
  297.             }
  298.             break;
  299.             }
  300.             clusters++;
  301.             prev = this;
  302.         }
  303.         if (this != curr)
  304.             die("Internal error: didn't find cluster %d in chain"
  305.               " starting at %d",curr,CF_LE_W(owner->dir_ent.start));
  306.         }
  307.         else {
  308.         if (prev) set_fat(fs,prev,-1);
  309.         else MODIFY(file,start,CT_LE_W(0));
  310.         break;
  311.         }
  312.     }
  313.     set_owner(fs,curr,file);
  314.     clusters++;
  315.     prev = curr;
  316.     }
  317.     if (!(file->dir_ent.attr & ATTR_DIR) && CF_LE_L(file->dir_ent.size) >
  318.       clusters*fs->cluster_size) {
  319.     printf("%s\n  File size is %u bytes, cluster chain length is %u bytes."
  320.       "\n  Truncating file to %u bytes.\n",path_name(file),CF_LE_L(file->
  321.       dir_ent.size),clusters*fs->cluster_size,clusters*fs->cluster_size);
  322.     MODIFY(file,size,CT_LE_L(clusters*fs->cluster_size));
  323.     }
  324.     return 0;
  325. }
  326.  
  327.  
  328. static int check_files(DOS_FS *fs,DOS_FILE *start)
  329. {
  330.     while (start) {
  331.     if (check_file(fs,start)) return 1;
  332.     start = start->next;
  333.     }
  334.     return 0;
  335. }
  336.  
  337.  
  338. static int check_dir(DOS_FS *fs,DOS_FILE **root,int dots)
  339. {
  340.     DOS_FILE *parent,**walk,**scan;
  341.     int dot,dotdot,skip,redo;
  342.     int good,bad;
  343.  
  344.     if (!*root) return 0;
  345.     parent = (*root)->parent;
  346.     good = bad = 0;
  347.     for (walk = root; *walk; walk = &(*walk)->next)
  348.     if (bad_name((*walk)->dir_ent.name)) bad++;
  349.     else good++;
  350.     if (*root && parent && good+bad > 4 && bad > good/2) {
  351.     printf("%s\n  Has a large number of bad entries. (%d/%d)\n",
  352.       path_name(parent),bad,good+bad);
  353.     if (!interactive) printf("  Dropping it.\n");
  354.     if (!interactive || get_key("yn","Drop directory ? (y/n)") == 'y') {
  355.         truncate_file(fs,parent,0);
  356.         MODIFY(parent,name[0],DELETED_FLAG);
  357.         /* buglet: deleted directory stays in the list. */
  358.         return 1;
  359.     }
  360.     }
  361.     dot = dotdot = redo = 0;
  362.     walk = root;
  363.     while (*walk) {
  364.     if (!strncmp((*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME) ||
  365.       !strncmp((*walk)->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME)) {
  366.         if (handle_dot(fs,*walk,dots)) {
  367.         *walk = (*walk)->next;
  368.         continue;
  369.         }
  370.         if (!strncmp((*walk)->dir_ent.name,MSDOS_DOT,MSDOS_NAME)) dot++;
  371.         else dotdot++;
  372.     }
  373.     if (bad_name((*walk)->dir_ent.name)) {
  374.         printf("%s\n  Bad file name.\n",path_name(*walk));
  375.         if (interactive)
  376.         printf("1) Drop file\n2) Rename file\n3) Auto-rename\n"
  377.           "4) Keep it\n");
  378.         else printf("  Auto-renaming it.\n");
  379.         switch (interactive ? get_key("1234","?") : '3') {
  380.         case '1':
  381.             drop_file(fs,*walk);
  382.             walk = &(*walk)->next;
  383.             continue;
  384.         case '2':
  385.             rename_file(*walk);
  386.             redo = 1;
  387.             break;
  388.         case '3':
  389.             auto_rename(*walk);
  390.             printf("  Renamed to %s\n",file_name((*walk)->dir_ent.
  391.               name));
  392.             break;
  393.         case '4':
  394.             break;
  395.         }
  396.     }
  397.     skip = 0;
  398.     scan = &(*walk)->next;
  399.     while (*scan && !skip) {
  400.         if (!strncmp((*walk)->dir_ent.name,(*scan)->dir_ent.name,MSDOS_NAME
  401.           )) {
  402.         printf("%s\n  Duplicate directory entry.\n  First  %s\n",
  403.           path_name(*walk),file_stat(*walk));
  404.         printf("  Second %s\n",file_stat(*scan));
  405.         if (interactive)
  406.             printf("1) Drop first\n2) Drop second\n3) Rename first\n"
  407.               "4) Rename second\n5) Auto-rename first\n"
  408.               "6) Auto-rename second\n");
  409.         else printf("  Auto-renaming second.\n");
  410.         switch (interactive ? get_key("123456","?") : '6') {
  411.             case '1':
  412.             drop_file(fs,*walk);
  413.             *walk = (*walk)->next;
  414.             skip = 1;
  415.             break;
  416.             case '2':
  417.             drop_file(fs,*scan);
  418.             *scan = (*scan)->next;
  419.             continue;
  420.             case '3':
  421.             rename_file(*walk);
  422.             printf("  Renamed to %s\n",path_name(*walk));
  423.             redo = 1;
  424.             break;
  425.             case '4':
  426.             rename_file(*scan);
  427.             printf("  Renamed to %s\n",path_name(*walk));
  428.             redo = 1;
  429.             break;
  430.             case '5':
  431.             auto_rename(*walk);
  432.             printf("  Renamed to %s\n",file_name((*walk)->dir_ent.
  433.               name));
  434.             break;
  435.             case '6':
  436.             auto_rename(*scan);
  437.             printf("  Renamed to %s\n",file_name((*scan)->dir_ent.
  438.               name));
  439.             break;
  440.         }
  441.         }
  442.         scan = &(*scan)->next;
  443.     }
  444.     if (skip) continue;
  445.     if (!redo) walk = &(*walk)->next;
  446.     else {
  447.         walk = root;
  448.         dot = dotdot = redo = 0;
  449.     }
  450.     }
  451.     if (dots && !dot)
  452.     printf("%s\n  \".\" is missing. Can't fix this yet.\n",
  453.       path_name(parent));
  454.     if (dots && !dotdot)
  455.     printf("%s\n  \"..\" is missing. Can't fix this yet.\n",
  456.       path_name(parent));
  457.     return 0;
  458. }
  459.  
  460.  
  461. static void test_file(DOS_FS *fs,DOS_FILE *file,int read_test)
  462. {
  463.     DOS_FILE *owner;
  464.     int walk,prev,clusters;
  465.  
  466.     prev = clusters = 0;
  467.     for (walk = CF_LE_W(file->dir_ent.start); walk > 0 && walk < fs->clusters+2;
  468.       walk = next_cluster(fs,walk)) {
  469.     if (owner = get_owner(fs,walk)) {
  470.         if (owner == file) {
  471.         printf("%s\n  Circular cluster chain. Truncating to %d "
  472.           "cluster%s.\n",path_name(file),clusters,clusters == 1 ? "" :
  473.           "s");
  474.         if (prev) set_fat(fs,prev,-1);
  475.         else MODIFY(file,start,CT_LE_W(0));
  476.         }
  477.         break;
  478.     }
  479.     if (bad_cluster(fs,walk)) break;
  480.     if (read_test)
  481.         if (fs_test(cluster_start(fs,walk),fs->cluster_size)) {
  482.         prev = walk;
  483.         clusters++;
  484.         }
  485.         else {
  486.         printf("%s\n  Cluster %d (%d) is unreadable. Skipping it.\n",
  487.           path_name(file),clusters,walk);
  488.         if (prev) set_fat(fs,prev,next_cluster(fs,walk));
  489.         else MODIFY(file,start,CT_LE_W(next_cluster(fs,walk)));
  490.         set_fat(fs,walk,-2);
  491.         }
  492.     set_owner(fs,walk,file);
  493.     }
  494.     for (walk = CF_LE_W(file->dir_ent.start); walk > 0 && walk < fs->clusters+2;
  495.       walk = next_cluster(fs,walk))
  496.     if (bad_cluster(fs,walk)) break;
  497.     else if (get_owner(fs,walk) == file) set_owner(fs,walk,NULL);
  498.         else break;
  499. }
  500.  
  501.  
  502. static void undelete(DOS_FS *fs,DOS_FILE *file)
  503. {
  504.     int clusters,left,prev,walk;
  505.  
  506.     clusters = left = (CF_LE_L(file->dir_ent.size)+fs->cluster_size-1)/
  507.       fs->cluster_size;
  508.     prev = 0;
  509.     for (walk = CF_LE_W(file->dir_ent.start); left && walk >= 2 && walk <
  510.        fs->clusters+2 && !fs->fat[walk].value; walk++) {
  511.     left--;
  512.     if (prev) set_fat(fs,prev,walk);
  513.     prev = walk;
  514.     }
  515.     if (prev) set_fat(fs,prev,-1);
  516.     else MODIFY(file,start,CT_LE_W(0));
  517.     if (left)
  518.     printf("Warning: Did only undelete %d of %d cluster%s.\n",clusters-left,
  519.       clusters,clusters == 1 ? "" : "s");
  520.    
  521. }
  522.  
  523.  
  524. static void add_file(DOS_FS *fs,DOS_FILE ***chain,DOS_FILE *parent,int offset,
  525.   FDSC **cp)
  526. {
  527.     DOS_FILE *new;
  528.     DIR_ENT de;
  529.     FD_TYPE type;
  530.  
  531.     fs_read(offset,sizeof(DIR_ENT),&de);
  532.     if ((type = file_type(cp,de.name)) != fdt_none) {
  533.     if (type == fdt_undelete && (de.attr & ATTR_DIR))
  534.         die("Can't undelete directories.");
  535.     file_modify(cp,de.name);
  536.     fs_write(offset,1,&de);
  537.     }
  538.     if (IS_FREE(de.name)) return;
  539.     new = qalloc(&mem_queue,sizeof(DOS_FILE));
  540.     new->offset = offset;
  541.     memcpy(&new->dir_ent,&de,sizeof(de));
  542.     new->next = new->first = NULL;
  543.     new->parent = parent;
  544.     if (type == fdt_undelete) undelete(fs,new);
  545.     **chain = new;
  546.     *chain = &new->next;
  547.     if (list) printf("Checking file %s\n",path_name(new));
  548.     test_file(fs,new,test);
  549. }
  550.  
  551.  
  552. static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp);
  553.  
  554.  
  555. static int scan_dir(DOS_FS *fs,DOS_FILE *this,FDSC **cp)
  556. {
  557.     DOS_FILE **chain;
  558.     int i,clu_num;
  559.  
  560.     chain = &this->first;
  561.     i = 0;
  562.     clu_num = CF_LE_W(this->dir_ent.start);
  563.     while (clu_num > 0) {
  564.     add_file(fs,&chain,this,cluster_start(fs,clu_num)+(i % fs->
  565.       cluster_size),cp);
  566.     i += sizeof(DIR_ENT);
  567.     if (!(i % fs->cluster_size))
  568.         if ((clu_num = next_cluster(fs,clu_num)) <= 0) break;
  569.     }
  570.     if (check_dir(fs,&this->first,1)) return 0;
  571.     if (check_files(fs,this->first)) return 1;
  572.     return subdirs(fs,this,cp);
  573. }
  574.  
  575.  
  576. static int subdirs(DOS_FS *fs,DOS_FILE *parent,FDSC **cp)
  577. {
  578.     DOS_FILE *walk;
  579.  
  580.     for (walk = parent ? parent->first : root; walk; walk = walk->next)
  581.     if (walk->dir_ent.attr & ATTR_DIR)
  582.         if (strncmp(walk->dir_ent.name,MSDOS_DOT,MSDOS_NAME) &&
  583.           strncmp(walk->dir_ent.name,MSDOS_DOTDOT,MSDOS_NAME))
  584.         if (scan_dir(fs,walk,file_cd(cp,walk->dir_ent.name))) return 1;
  585.     return 0;
  586. }
  587.  
  588.  
  589. int scan_root(DOS_FS *fs)
  590. {
  591.     DOS_FILE **chain;
  592.     int i;
  593.  
  594.     root = NULL;
  595.     chain = &root;
  596.     for (i = 0; i < fs->root_entries; i++)
  597.     add_file(fs,&chain,NULL,fs->root_start+i*sizeof(DIR_ENT),&fp_root);
  598.     (void) check_dir(fs,&root,0);
  599.     if (check_files(fs,root)) return 1;
  600.     return subdirs(fs,NULL,&fp_root);
  601. }
  602.